﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace DCT.CodeBox.TaskManager.Codes
{
    /// <summary>
    /// 队列执行任务调度，执行完立刻移除任务
    /// </summary>
    public class QueueTaskDispatcher : TaskDispatcher
    {
        /// <summary>
        /// 信号对象
        /// </summary>
        private AutoResetEvent signal;

        /// <summary>
        /// 构造函数
        /// </summary>
        public QueueTaskDispatcher()
        {
        }

        /// <summary>
        /// 队列服务均会执行，所以永远返回true
        /// </summary>
        /// <param name="config"></param>
        /// <returns></returns>
        protected override bool ValidExecuteTaskItem(object config)
        {
            return true;
        }

        /// <summary>
        /// 执行所有任务时的锁，防止任务多个线程竞争循环执行
        /// </summary>
        private object lockExecuteAllTask = new object();

        /// <summary>
        /// 启动
        /// </summary>
        /// <remarks>Start会清空所有原有的队列，重新启动</remarks>
        public override void Start()
        {
            if (this.IsActive)
            {
                return; //无需重复启动
            }
            base.Start();

            lock (lockExecuteAllTask)
            {
                //清除任务
                this.wrappers.Clear();
            }

            //如果原来的信号还存在，便销毁
            if (signal != null)
            {
                signal.Close();
                signal.Dispose();
                signal = null;
            }
            //重新建一个新的信号
            signal = new AutoResetEvent(false);

            ThreadPool.QueueUserWorkItem(delegate   //异步执行
            {
                while (true)
                {
                    if (signal.WaitOne())   //线程阻塞
                    {
                        if (!this.IsActive) //如果非活动状态，跳出循环
                        {
                            break;
                        }
                        //获取信号信息，执行任务
                        lock (lockExecuteAllTask)
                        {
                            this.ExecuteAllTask();
                        }
                    }
                }
            });
        }

        /// <summary>
        /// 恢复执行
        /// </summary>
        public override void Resume()
        {
            if (this.IsActive)
            {
                return; //无需重复启动
            }
            if (this.Status == TaskDispatcherStatus.Idle)
            {
                return; //需要使用Start启动
            }

            base.Resume();

            ThreadPool.QueueUserWorkItem(delegate   //异步执行
            {
                lock (lockExecuteAllTask)
                {
                    //一开始就执行任务，处理在pause时期积累的任务列表
                    this.ExecuteAllTask();
                }
                while (true)
                {
                    if (signal.WaitOne())   //线程阻塞
                    {
                        if (!this.IsActive)
                        {
                            break;
                        }
                        //获取信号信息，执行任务
                        lock (lockExecuteAllTask)
                        {
                            this.ExecuteAllTask();
                        }
                    }
                }
            });
        }

        /// <summary>
        /// 暂停
        /// </summary>
        public override void Pause()
        {
            if (signal == null)
            {
                return;
            }
            //不活动就不需要暂停
            if (!this.IsActive)
            {
                return;
            }
            base.Pause();
            //发信号通知
            this.signal.Set();
        }

        /// <summary>
        /// 停止
        /// </summary>
        public override void Stop()
        {
            if (signal == null)
            {
                return;
            }
            base.Stop();
            lock (this.lockWrapper)
            {
                this.wrappers.Clear();
            }
            //销毁信号
            if (signal != null)
            {
                signal.Close();
                signal.Dispose();
                signal = null;
            }
        }

        /// <summary>
        /// 添加任务
        /// </summary>
        /// <param name="taskItem">任务执行</param>
        /// <param name="arg">任务执行参数</param>
        /// <param name="config">Dispatcher配置</param>
        public override void AddTaskItem(ITaskItem taskItem, object arg, object config)
        {
            base.AddTaskItem(taskItem, arg, config);
            if (this.IsActive)
            {
                this.signal.Set();
            }
        }

        /// <summary>
        /// 批量添加任务
        /// </summary>
        /// <param name="tasks"></param>
        public override void AddTaskItemRange(List<TaskItemWrapper> tasks)
        {
            base.AddTaskItemRange(tasks);
            if (this.IsActive)
            {
                this.signal.Set();
            }
        }

        /// <summary>
        /// 循环执行所有任务
        /// </summary>
        private void ExecuteAllTask()
        {
            //为了减少对this.wrappers的lock，就复制一份队列再进行循环执行
            TaskItemWrapper[] copies = null;
            lock (this.lockWrapper)
            {
                copies = new TaskItemWrapper[this.wrappers.Count];
                this.wrappers.CopyTo(copies);
                this.wrappers.Clear();
            }

            int wrapperLeft = -1;   //记录暂停时的队列索引
            //循环执行
            for (int i = 0; i < copies.Length; i++)
            {
                TaskItemWrapper wrapper = copies[i];
                bool isContinue = this.ExecuteTaskItem(wrapper);
                if (!isContinue)
                {
                    if (this.Status == TaskDispatcherStatus.Pause)
                    {
                        //如果Break，是由于暂停，则要把剩余的任务留下来插入到现有任务的开头；以便再次Resume的时候可以立刻执行
                        wrapperLeft = i;
                    }
                    break;
                }
            }

            if (wrapperLeft > -1)
            { 
                //有遗留任务队列需要执行，放到任务的最前端等待下次resume一开始就可以执行
                TaskItemWrapper[] lefts = new TaskItemWrapper[copies.Length - wrapperLeft];
                Array.Copy(copies, wrapperLeft, lefts, 0, lefts.Length);
                lock (this.lockWrapper)
                {
                    //把遗留任务放到最前端
                    this.wrappers.InsertRange(0, lefts);
                }
            }
        }
    }
}
